/*
 * File Name:               XTexture2D.cs
 * 
 * Description:             普通类
 * Author:                  lisiyu <576603306@qq.com>

 * Create Date:             2017/07/21
 */

using UnityEngine;
using System;

public class XTexture2D
{
    public const int CHANNEL_LENGTH = 7;

    public int[] channels;
    public byte[] r;
    public byte[] g;
    public byte[] b;

    public int width;
    public int height;

    public XTexture2D(int width, int height, Texture2D[] texture2ds)
    {
        this.width = width;
        this.height = height;

        var length = width * height;
        channels = new int[length];
        r = new byte[length];
        g = new byte[length];
        b = new byte[length];

        for (int i = 0; i < texture2ds.Length; i++)
        {
            var tex = texture2ds[i].resizeBilinear(width, height);
            tex.Apply();
            var pixs = tex.GetPixels();
            for (int j = 0; j < length; j++)
            {
                if (i == texture2ds.Length - 1)
                {
                    setRGB(j, pixs[j]);
                }
                else
                {
                    setChannel(j, i, pixs[j]);
                }
            }
        }
    }

    public XTexture2D(byte[] bytes)
    {
        width = BitConverter.ToInt32(bytes, 0);
        height = BitConverter.ToInt32(bytes, 4);

        var length = width * height;
        channels = new int[length];
        r = new byte[length];
        g = new byte[length];
        b = new byte[length];

        var startIndex = 8;
        for (int i = 0; i < length; i++)
        {
            var index = startIndex + i;
            r[i] = bytes[index];
            g[i] = bytes[index + length];
            b[i] = bytes[index + length + length];
            channels[i] = BitConverter.ToInt32(bytes, startIndex + length + length + length + i * 4);
        }
    }

    private void setRGB(int index, Color color)
    {
        r[index] = (byte)(color.r * byte.MaxValue);
        g[index] = (byte)(color.g * byte.MaxValue);
        b[index] = (byte)(color.b * byte.MaxValue);
    }

    private void setChannel(int index, int channel, Color color)
    {
        if (color.a > 0f)
            channels[index] += (Mathf.CeilToInt(color.a * 15)) << (channel * 4);
    }

    public Texture2D parse(Color[] colors)
    {
        var ret = new Texture2D(this.width, this.height, TextureFormat.RGB24, false);
        var length = width * height;
        var texPiexls = new Color[length];
        ret.SetPixels(parse(colors, texPiexls));
        ret.Compress(true);
        ret.Apply(false, true);
        return ret;
    }

    public void parse(Texture2D ret, Color[] colors)
    {
        var length = width * height;
        var texPiexls = new Color[length];
        ret.SetPixels(parse(colors, texPiexls));
    }

    public Texture2D parseWithoutCompressAndReadable(Color[] colors)
    {
        var ret = new Texture2D(this.width, this.height, TextureFormat.RGB24, false);
        var length = width * height;
        var texPiexls = new Color[length];
        ret.SetPixels(parse(colors, texPiexls));
        return ret;
    }

    public void parse(Texture2D ret, Color[] colors, Color[] texPiexls)
    {
        ret.SetPixels(parse(colors, texPiexls));
    }

    public Color[] parse(Color[] colors, Color[] texPiexls)
    {
        var length = width * height;
        var byte2Float = 1f / byte.MaxValue;

        for (int i = 0; i < length; i++)
        {
            texPiexls[i].r = 1f;
            texPiexls[i].g = 1f;
            texPiexls[i].b = 1f;

            for (int j = 0; j < CHANNEL_LENGTH; j++)
            {
                var channel = (channels[i] >> (j * 4)) & 0x0000000f;
                if (channel > 0)
                {
                    var a = channel / 15f;
                    if (a == 0f) continue;

                    if (a < 1f)
                    {
                        texPiexls[i].r = texPiexls[i].r * (1f - a) + colors[j].r * r[i] * byte2Float * a;
                        texPiexls[i].g = texPiexls[i].g * (1f - a) + colors[j].g * g[i] * byte2Float * a;
                        texPiexls[i].b = texPiexls[i].b * (1f - a) + colors[j].b * b[i] * byte2Float * a;
                    }
                    else
                    {
                        texPiexls[i].r = colors[j].r * r[i] * byte2Float;
                        texPiexls[i].g = colors[j].g * g[i] * byte2Float;
                        texPiexls[i].b = colors[j].b * b[i] * byte2Float;
                    }
                }
            }
        }

        return texPiexls;
    }

    public byte[] toBytes()
    {
        var bytes = new byte[4 + 4 + r.Length + g.Length + b.Length + channels.Length * 4];
        Array.Copy(BitConverter.GetBytes(width), 0, bytes, 0, 4);
        Array.Copy(BitConverter.GetBytes(height), 0, bytes, 4, 4);
        Array.Copy(r, 0, bytes, 8, r.Length);
        Array.Copy(g, 0, bytes, 8 + r.Length, g.Length);
        Array.Copy(b, 0, bytes, 8 + r.Length + g.Length, b.Length);

        for (int i = 0; i < channels.Length; i++)
        {
            Array.Copy(BitConverter.GetBytes(channels[i]), 0, bytes, 8 + r.Length + g.Length + b.Length + i * 4, 4);
        }

        return bytes;
    }
}